package yunjiao.javatutorials.guava.concurrent;

import com.google.common.util.concurrent.Monitor;

/**
 * 状态机
 *
 * @author yangyunjiao
 */
public class StateMachine {
    private final Monitor monitor = new Monitor();

    public enum State {
        INIT, PROCESSING, PAUSED, COMPLETED, ERROR
    }

    private State currentState = State.INIT;
    private int progress = 0;

    // 状态转换条件
    private final Monitor.Guard canStart = new Monitor.Guard(monitor) {
        @Override
        public boolean isSatisfied() {
            return currentState == State.INIT || currentState == State.PAUSED;
        }
    };

    private final Monitor.Guard canPause = new Monitor.Guard(monitor) {
        @Override
        public boolean isSatisfied() {
            return currentState == State.PROCESSING;
        }
    };

    private final Monitor.Guard canResume = new Monitor.Guard(monitor) {
        @Override
        public boolean isSatisfied() {
            return currentState == State.PAUSED;
        }
    };

    private final Monitor.Guard canComplete = new Monitor.Guard(monitor) {
        @Override
        public boolean isSatisfied() {
            return currentState == State.PROCESSING && progress >= 100;
        }
    };

    public void start() throws InterruptedException {
        monitor.enterWhen(canStart);
        try {
            if (currentState == State.INIT) {
                progress = 0;
            }
            currentState = State.PROCESSING;
            System.out.println("State changed to: " + currentState);
        } finally {
            monitor.leave();
        }
    }

    public void pause() throws InterruptedException {
        monitor.enterWhen(canPause);
        try {
            currentState = State.PAUSED;
            System.out.println("State changed to: " + currentState);
        } finally {
            monitor.leave();
        }
    }

    public void resume() throws InterruptedException {
        monitor.enterWhen(canResume);
        try {
            currentState = State.PROCESSING;
            System.out.println("State changed to: " + currentState);
        } finally {
            monitor.leave();
        }
    }

    public void complete() throws InterruptedException {
        monitor.enterWhen(canComplete);
        try {
            currentState = State.COMPLETED;
            System.out.println("State changed to: " + currentState);
        } finally {
            monitor.leave();
        }
    }

    public void error() {
        monitor.enter();
        try {
            currentState = State.ERROR;
            System.out.println("State changed to: " + currentState);
        } finally {
            monitor.leave();
        }
    }

    public void updateProgress(int newProgress) {
        monitor.enter();
        try {
            if (currentState == State.PROCESSING) {
                progress = Math.min(100, Math.max(0, newProgress));
                System.out.println("Progress updated to: " + progress + "%");

                // 检查是否可以自动完成
                if (progress >= 100 && canComplete.isSatisfied()) {
                    currentState = State.COMPLETED;
                    System.out.println("Auto-completed! State: " + currentState);
                }
            }
        } finally {
            monitor.leave();
        }
    }

    public State getCurrentState() {
        monitor.enter();
        try {
            return currentState;
        } finally {
            monitor.leave();
        }
    }

    public int getProgress() {
        monitor.enter();
        try {
            return progress;
        } finally {
            monitor.leave();
        }
    }

    // 等待特定状态
    public void waitForState(State targetState) throws InterruptedException {
        Monitor.Guard stateReached = new Monitor.Guard(monitor) {
            @Override
            public boolean isSatisfied() {
                return currentState == targetState;
            }
        };

        monitor.enterWhen(stateReached);
        monitor.leave();
    }
}
